﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using GalaSoft.MvvmLight.Messaging;
using NLog;
using SellAvi.Classes;
using SellAvi.Properties;
using SellAvi.Schemas;
using SellAvi.Views;

namespace SellAvi.ViewModel
{
    public class AdsActivatorViewModel : ViewModelBase
    {
        private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
        public RelayCommand ReActivateCommand { get; set; }
        public RelayCommand GetCategoriesCommand { get; set; }
        public RelayCommand ShowCategoriesCommand { get; set; }
        public RelayCommand RegroupCommand { get; set; }
        public RelayCommand RecalculateActivationItemsCommand { get; set; }
        public RelayCommand UnCheckAllCommand { get; set; }
        private readonly ActivatorSchema _sps;
        public WebClientEx Webclient { get; set; }

        public ObservableCollection<AvitoSearchItem> SearchIndexCollection { get; set; }
        public ObservableCollection<CheckableItem> CheckableActivationCategories { get; set; }

        private bool _isActivationEnabled;
        public bool IsActivationEnabled
        {
            get { return SearchIndexCollection.Count > 0; }
        }


        public int ActivationSpeed { get; set; }

        private int _pageCounter;
        public int PageCounter
        {
            get { return _pageCounter; }
            set
            {
                _pageCounter = value;
                RaisePropertyChanged("PageCounter");
            }
        }

        private int _unactiveAdsCount;

        public int UnactiveAdsCount //тоже самое что и SearchIndexCollection.Count
        {
            get { return _unactiveAdsCount; }
            set
            {
                _unactiveAdsCount = value;
                RaisePropertyChanged("UnactiveAdsCount");
            }
        }
        private int _selectedAdsCount;
        public int SelectedAdsCount
        {
            get { return _selectedAdsCount; }
            set
            {
                _selectedAdsCount = value;
                RaisePropertyChanged("SelectedAdsCount");
            }
        }

        public AdsActivatorViewModel()
        {
            SearchIndexCollection = new ObservableCollection<AvitoSearchItem>();
            ActivationSpeed = Settings.Default.ActivationTimeOut;
            UnactiveAdsCount = 0;
            PageCounter = 0;
            _sps = new ActivatorSchema();

            ReActivateCommand = new RelayCommand(CreateActivationTask);
            GetCategoriesCommand = new RelayCommand(AnalysePages);
            ShowCategoriesCommand = new RelayCommand(ShowCategories);
            RegroupCommand = new RelayCommand(RegroupActivationItems);
            UnCheckAllCommand = new RelayCommand(UnCheckAll);
            RecalculateActivationItemsCommand = new RelayCommand(RecalculateActivationItems);

            Messenger.Default.Register<WebClientEx>(this, (receivedClient) => { this.Webclient = receivedClient; });
        }


        private void ShowCategories()
        {
            if (CheckableActivationCategories == null)
            {
                RegroupActivationItems();
                RecalculateActivationItems();
            }
            new WindowSiteCategories().Show();
        }

        private void RegroupActivationItems()
        {
            var unique = SearchIndexCollection.Select(x => x.GetUrlSegment(SelectedMode)).Distinct().Select(x => new CheckableItem() { IsChecked = true, LabelName = x });
            CheckableActivationCategories = new ObservableCollection<CheckableItem>(unique);
            RaisePropertyChanged("CheckableActivationCategories");
            RecalculateActivationItems();
        }
        private void UnCheckAll()
        {
            var unique = SearchIndexCollection.Select(x => x.GetUrlSegment(SelectedMode)).Distinct().Select(x => new CheckableItem() { IsChecked = false, LabelName = x });
            CheckableActivationCategories = new ObservableCollection<CheckableItem>(unique);
            RaisePropertyChanged("CheckableActivationCategories");
            RecalculateActivationItems();
        }

        private void RecalculateActivationItems()
        {
            SelectedAdsCount = (from activationItem in SearchIndexCollection
                                join checkedSegment in CheckableActivationCategories on activationItem.GetUrlSegment(SelectedMode)
                                    equals checkedSegment.LabelName
                                where checkedSegment.IsChecked
                                select activationItem).Count();
        }

        private void CreateActivationTask()
        {
            var taskList = new List<AvitoTask>();
            foreach (var item in SearchIndexCollection)
            {
                if (CheckableActivationCategories.Any(x => (x.LabelName == item.GetUrlSegment(SelectedMode) && x.IsChecked == false)))
                {
                    continue;
                }
                var tms = new TaskActivator((AvitoSearchItem)item) { TaskDelay = ActivationSpeed };
                taskList.Add(tms);
            }
            Messenger.Default.Send<List<AvitoTask>>(taskList);
        }

        private bool _parseInProgress;
        public bool ParseInProgress
        {
            get { return _parseInProgress; }
            set
            {
                _parseInProgress = value;
                RaisePropertyChanged("ParseInProgress");
                RaisePropertyChanged("IsActivationEnabled");
            }
        }
        private void AnalysePages()
        {
            if (Webclient != null)
            {
                if (!ParseInProgress)
                {
                    ParseInProgress = true;
                    PageCounter = (PageCounter == 0) ? 1 : PageCounter;

                    Task.Factory.StartNew(_ => ParseIndex(Settings.Default.ActivationPagesNum), new CancellationTokenSource())
                        .ContinueWith(_ => { ParseInProgress = false; });
                }
            }
            else
            {
                MessageBox.Show("Для выполнения операции необходима авторизация в программе!", "Требуется авторизация", MessageBoxButton.OK,
                    MessageBoxImage.Asterisk);
            }

        }
        private void ParseIndex(int numPages)
        {
            var countTo = PageCounter + numPages - 1;
            var app = new AvitoParserProcessor(Webclient, _sps);
            while (PageCounter < countTo)
            {
                var pagingLink = new Uri(String.Format(_sps.PagingTemplate, PageCounter));
                var indexItems = app.DownloadIndexUrlsAsync(pagingLink).Result;
                Logger.Trace("Обработана страница {0}", pagingLink);
                foreach (var item in indexItems)
                {
                    SearchIndexCollection.Add(item);
                    UnactiveAdsCount++;
                }
                PageCounter++;
                /*
                var htmlPage = new HtmlDocument();
                htmlPage.LoadHtml(Webclient.ResponseHtml);
                if (htmlPage.DocumentNode.SelectSingleNode(_sps.XPathNextPage) == null)
                    break;
                */

            }
        }

        private bool[] _modeArray = new bool[] { false, false, true, false };

        public bool[] ModeArray
        {
            get { return _modeArray; }
        }
        public int SelectedMode
        {
            get
            {
                for (int i = 0; i < _modeArray.Length; i++)
                    if (_modeArray[i]) return i;
                return -1;
            }
        }
    }
    public class CheckableItem
    {
        public bool IsChecked { get; set; }
        public string LabelName { get; set; }
    }
}
